package com.gwd.task.services.impl;

import com.gwd.task.entity.ProjectModuleEntity;
import com.gwd.task.model.ProjectModuleDTO;
import com.gwd.task.model.TaskDTO;
import com.gwd.task.repository.ProjectModuleRepository;
import com.gwd.task.services.ProjectModuleServer;
import com.gwd.task.services.TaskServer;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhiyongming
 * @date 2020/11/19 19:10
 */
@Service
public class ProjectModuleServerImpl implements ProjectModuleServer {

    @Resource
    private ProjectModuleRepository projectModuleRepository;
    @Resource
    private TaskServer taskServer;

    @Override
    public List<ProjectModuleDTO> findAll() {
        return projectModuleRepository.findAll().stream().map(ProjectModuleDTO::new).collect(Collectors.toList());
    }

    @Override
    public List<ProjectModuleDTO> findByProject(Long projectId) {
        List<Long> idList = new ArrayList<>();
        idList.add(projectId);
        return findByProjectIdList(idList);
    }

    @Override
    public List<ProjectModuleDTO> findByProjectIdList(List<Long> idList) {
        List<ProjectModuleEntity> list = projectModuleRepository.findByProjectIdIn(idList);
        if (list==null) {
            return new ArrayList<>();
        }

        //匹配所属任务
        List<TaskDTO> tasks =
                taskServer.findByModuleIdList(list.stream().map(ProjectModuleEntity::getModuleId).collect(Collectors.toList()));
        List<ProjectModuleDTO> ss = list.stream().map(ProjectModuleDTO::new).collect(Collectors.toList());
        ss.forEach(s -> tasks.forEach(t -> {
            if (s.getModuleId().equals(t.getModuleId()[1])) {
                s.addTask(t);
            }
        }));

        //树结构生成
        List<ProjectModuleDTO> dtoList = new ArrayList<>();
        for (ProjectModuleDTO dto : ss) {
            if (dto.getSuperior().equals(-1L)) {
                dtoList.add(dto);
                continue;
            }
            dtoList.forEach(d -> {
                if (d.getModuleId().equals(dto.getSuperior())) {
                    d.addChildren(dto);
                }
            });
        }

        return dtoList;
    }

    @Override
    public List<ProjectModuleDTO> findByGroup(Long groupId) {
        ProjectModuleEntity entity = new ProjectModuleEntity();
        entity.setGroupId(groupId);
        return projectModuleRepository.findAll(Example.of(entity)).stream().map(ProjectModuleDTO::new).collect(Collectors.toList());
    }

    @Override
    public void save(Long projectId, Long groupId, List<ProjectModuleDTO> dtoList) {
        /*
         * 1: 获取之前已保存的模块
         * 2: 把传入的模块列表中，id为0的存入需要保存的
         * 3: 通过新旧比较差集，把需要删除的id列表列出
         * 4: 通过id删除
         * 5: 新增需要新增的
         */
        List<ProjectModuleDTO> list = findByProject(projectId);

        List<ProjectModuleDTO> needAdd
                = dtoList.stream()
                .filter(item -> item.getProjectId()==null||item.getProjectId()==0).collect(Collectors.toList());
        needAdd.addAll(
            dtoList.stream().filter(item -> item.getModuleId()!=0L).collect(Collectors.toList()));

        List<Long> needDelete = extractIdList(list).stream()
                                    .filter(id -> !extractIdList(dtoList).contains(id))
                                    .collect(Collectors.toList());
        projectModuleRepository.deleteByIdList(needDelete);
        projectModuleRepository.deleteBySuperiorIn(needDelete);
        projectModuleRepository.saveAll(needAdd.stream().peek(e-> {
            e.setGroupId(groupId);
            e.setProjectId(projectId);
        }).map(ProjectModuleEntity::new).collect(Collectors.toList()));

    }

    @Override
    public void saveV2(Long projectId, Long groupId, List<ProjectModuleDTO> dtoList) {
        // 新增一级和删除
        save(projectId, groupId, dtoList);

        // 新增二级
        List<ProjectModuleEntity> needSave = new ArrayList<>();
        List<ProjectModuleDTO> list = findByProject(projectId);
        List<ProjectModuleEntity> lv2 = projectModuleRepository.findByProjectId(projectId).stream().filter(e->e.getSuperior()!=-1L).collect(Collectors.toList());
        List<Long> lv2Tmp = new ArrayList<>();
        list.forEach(d -> dtoList.forEach(n -> {
            if (d.getModuleName().equals(n.getModuleName())) {
                // d是刚刚插入数据库表的一级列表
                if (d.getChildren()!=null || n.getChildren()!=null) {
                    List<ProjectModuleDTO> children = n.getChildren();
                    children.forEach(c -> {
                        if (c.getModuleId()==0) {
                            ProjectModuleEntity entity = new ProjectModuleEntity();
                            entity.setSuperior(d.getModuleId());
                            entity.setModuleName(c.getModuleName());
                            entity.setProjectId(projectId);
                            entity.setGroupId(groupId);
                            needSave.add(entity);
                        }
                        for (int i = 0; i < lv2.size(); i++) {
                            if (lv2.get(i).getModuleId().equals(c.getModuleId())) {
                                lv2.get(i).setModuleName(c.getModuleName());
                                needSave.add(lv2.get(i));
                                lv2Tmp.add((long) i);
                            }
                        }
                    });
                }
            }
        }));
        Collections.reverse(lv2Tmp);
        lv2Tmp.forEach(j -> {
            for (int i = lv2.size() - 1; i >= 0; i--) {
                if (i==j) {
                    lv2.remove(i);
                }
            }
        });

        List<Long> ids = lv2.stream().map(ProjectModuleEntity::getModuleId).collect(Collectors.toList());
        projectModuleRepository.saveAll(needSave);
        if (ids.size()>0) {
            projectModuleRepository.deleteByIdList(ids);
        }
    }

    private static List<Long> extractIdList(List<ProjectModuleDTO> list) {
        return list.stream().map(ProjectModuleDTO::getModuleId).collect(Collectors.toList());
    }
}
